package hibernate;

import java.util.Iterator;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

import model.*;

/**
 * Clase con consultas HQL
 */
public class Queries {
	
	private static SessionFactory sessions;
	
	private static Session session;
	
	public static void main(String[] args) {
		try {
			// Configuro Hibernate
			cfgHibernate();
			session = sessions.openSession();
			
			// Ejecuto cada una de las consultas
			getNombreSeries();
			getNombreSeries("a");
			get5EpisodiosMasVistos();
			getPeliculaMasVistaDelAnio(2012);
			getUsuariosReproMasNPeliculas(200L);
			getUsuariosQVieronAlmenos1Episodio();
			getNPeliculasMasVistas(7);
			getUsuariosQueVieron("Be a Friend");
			getUsuariosEdadm12QueVieronAlmenos1Peli();
			getUsuariosAlimiteDeUnaCategoria(30);

			session.disconnect();
			
		} catch (Exception e) {
			session.close();
			System.out.println("------------------------FAIL.------------------------");
			e.printStackTrace();
		}
	}
	
	/**
	 * Configuracion de Hibernate
	 */	
	private static void cfgHibernate(){
		System.out.println("----------------------- Setting up Hibernate -----------------------");
		Configuration cfg = new Configuration();
		cfg.configure("hibernate/hibernate.cfg.xml");
		sessions = cfg.buildSessionFactory();
	}
	
	/**
	 * @return Retorna Todos los titulos de las series
	 */
	private static void getNombreSeries(){
		Transaction tx = null;
		try {
			Query query = session.createQuery("from Serie");

			tx = session.beginTransaction();
			List list =  query.list();
			tx.commit();

			System.out.println("-----------------------------------------------------------------------------");
			System.out.println("a. Listar el nombre de todas las series del sistema. ");
			System.out.println("-----------------------------------------------------------------------------");

			Iterator iter = list.iterator();
			while( iter.hasNext()){
				Serie serie = (Serie) iter.next();
				System.out.println("   T�tulo de la Serie: " + serie.getTitulo());
			}
			
			System.out.println("-----------------------------------------------------------------------------");

		} catch (Exception e) {
			e.printStackTrace();
			if (tx != null) {
				tx.commit();
			}
		}
	}

	/**
	 * @return Lista Todos los titulos de las series que contengan una secuencia de caracteres que se pasa comoparametro
	 * @param Secuencia de caracteres que debe estar contenida en el nombre de la serie
	 */
	private static void getNombreSeries(String s){
		Transaction tx = null;
		try {
			Query query = session.createQuery("from Serie s where s.titulo like :param");
			query.setParameter("param", "%"+s+"%");

			tx = session.beginTransaction();			
			List list =  query.list();
			tx.commit();

			System.out.println("-----------------------------------------------------------------------------");
			System.out.println("b. Listar las series cuyo t�tulo contenga una secuencia de caracteres: '" + s + "'");
			System.out.println("-----------------------------------------------------------------------------");

			Iterator iter = list.iterator();
			while( iter.hasNext()){
				Serie serie = (Serie) iter.next();
				System.out.println("   T�tulo de la Serie: " + serie.getTitulo());
			}
			
			System.out.println("-----------------------------------------------------------------------------");

		} catch (Exception e) {
			e.printStackTrace();
			if (tx != null) {
				tx.commit();
			}
		}
	}	

	/**
	 * @return Lista los 5 episodios de series m�s vistos en el sistema.
	 */
	private static void get5EpisodiosMasVistos(){
		Transaction tx = null;
		try {
			Query query = session.createQuery(
					"select e, count(*) as cantidad "+
					"from Reproduccion r, Episodio e " +
			        "where  r.Reproducible.class='Episodio' and r.Reproducible.id=e.id " + 
					"group by e order by count(*) desc");
			query.setMaxResults(5);

			tx = session.beginTransaction();			
			List list =  query.list();
			tx.commit();

			System.out.println("-----------------------------------------------------------------------------");
			System.out.println("c. Listar los 5 episodios de series m�s vistos en el sistema. ");
			System.out.println("-----------------------------------------------------------------------------");

			Iterator iter = list.iterator();
			while( iter.hasNext()){
				Object[] objs= (Object[]) iter.next();
				System.out.println("   La serie: " +  ((Episodio)objs[0]).getTitulo() + " ha sido vista "  + objs[1].toString() + " veces." );
			}

		} catch (Exception e) {
			e.printStackTrace();
			if (tx != null) {
				tx.commit();
			}
		}
		System.out.println("-----------------------------------------------------------------------------");
	}

	/**
	 * @param anio de reproduccion de la pelicula
	 * @return Listar la pelicula mas vista en el a�o que se pasa como parametro
	 */
	private static void getPeliculaMasVistaDelAnio(Integer anio){
		Transaction tx = null;
		try {
			Query query = session.createQuery(
					"select p, count(*) as cantidad "+
					"from Reproduccion r, model.Pelicula p " +
			        "where  r.Reproducible.class='Pelicula' and r.Reproducible.id=p.id and year(r.fecha) = :anio " + 
					"group by p order by count(*) desc");
			query.setParameter("anio", anio);
			query.setMaxResults(1);

			tx = session.beginTransaction();
			List list =  query.list();
			tx.commit();

			System.out.println("-----------------------------------------------------------------------------");
			System.out.println("d. Informar la pel�cula m�s vista en el a�o: "+ anio.toString());
			System.out.println("-----------------------------------------------------------------------------");
			
			Iterator iter = list.iterator();
			while( iter.hasNext()){
				Object[] objs= (Object[]) iter.next();
				System.out.println("   El t�tulo de la Pel�cula m�s vista en el a�o: "+ anio.toString() +  " es: " + ((Pelicula)objs[0]).getTitulo() );
			}

		} catch (Exception e) {
			e.printStackTrace();
			if (tx != null) {
				tx.commit();
			}
		}

		System.out.println("-----------------------------------------------------------------------------");
	}
	
	/**
	 * @param cantidad de peliculas
	 * @return Lista los usuarios que reprodujeron m�s de n peliculas
	 */
	private static void getUsuariosReproMasNPeliculas(Long n){
		Transaction tx = null;
		try {
			Query query = session.createQuery(
					"select u.email, count(*) as cantidad " +
					"from Usuario u inner join u.gestor g inner join g.reproducciones r " +
					"where r.Reproducible.class = 'Pelicula' " +
					"group by email having count(*) > :n " +
					"order by count(*) desc "
			);
			query.setParameter("n", n);
			
			tx = session.beginTransaction();
			List list =  query.list();
			tx.commit();

			System.out.println("---------------------------------------------------------------------------------------");
			System.out.println("e. Listar los usuarios que reprodujeron m�s de " + n.toString() + " pel�culas.");
			System.out.println("---------------------------------------------------------------------------------------");

			Iterator iter = list.iterator();
			while( iter.hasNext()){
				Object[] objs= (Object[]) iter.next();
				System.out.println("   El usuario con mail: " +  (String)objs[0] + " ha realizado "  + objs[1].toString() + " reproducciones." );
			}

		} catch (Exception e) {
			e.printStackTrace();
			if (tx != null) {
				tx.commit();
			}
		}
		
		System.out.println("---------------------------------------------------------------------------------------");
	}

	/**
	 * @return Lista los usuarios que vieron al menos un episodio por menos de 65 segundos (65000 milisegundos).
	 */
	private static void getUsuariosQVieronAlmenos1Episodio(){
		Transaction tx = null;
		try {
			Query query = session.createQuery(
					"select distinct u.email " +
					"from Usuario u inner join u.gestor g inner join g.reproducciones r " +
					"where r.tiempo < 65000 ) "
			);
			
			tx = session.beginTransaction();
			List list =  query.list();
			tx.commit();

			System.out.println("-----------------------------------------------------------------------------");
			System.out.println("f. Listar los usuarios que vieron al menos un episodio por menos de 65 seg");
			System.out.println("   (65000 milisegundos).");
			System.out.println("-----------------------------------------------------------------------------");
			
			Iterator iter = list.iterator();
			while( iter.hasNext()){
				Object obj= (Object) iter.next();
				System.out.println("   Mail del usuario: " +  (String)obj );
			}

		} catch (Exception e) {
			e.printStackTrace();
			if (tx != null) {
				tx.commit();
			}
		}
		
		System.out.println("-----------------------------------------------------------------------------");
		
	}
	
	/**
	 * @param top n
	 * @return Listar las n pel�culas m�s vistas en el sistema.
	 */
	private static void getNPeliculasMasVistas(Integer n){
		// Session session = sessions.openSession();
		Transaction tx = null;
		try {
			Query query = session.createQuery(
					"select p, count(*) as cantidad "+
					"from Reproduccion r, model.Pelicula p " +
			        "where  r.Reproducible.class='Pelicula' and r.Reproducible.id=p.id " + 
					"group by p order by count(*) desc");
			query.setMaxResults(n);
			
			tx = session.beginTransaction();
			List list =  query.list();
			tx.commit();

			System.out.println("-----------------------------------------------------------------------------");
			System.out.println("g. Listar las " + n.toString() +" pel�culas m�s vistas en el sistema.");
			System.out.println("-----------------------------------------------------------------------------");
			
			Iterator iter = list.iterator();
			while( iter.hasNext()){
				Object[] objs= (Object[]) iter.next();
				System.out.println("   La pelicula: " +  ((Pelicula)objs[0]).getTitulo() + " ha sido vista "  + objs[1].toString() + " veces." );
			}

		} catch (Exception e) {
			e.printStackTrace();
			if (tx != null) {
				tx.commit();
			}
			//session.close();
		}
		//session.disconnect();
		
		System.out.println("-----------------------------------------------------------------------------");
	}
	
	/**
	 * @param titulo
	 * @return Listar los usuarios que vieron un episodio cuyo título se ingresa por parámetro. Imprimir en
consola:"Mail del usuario.
	 */
	private static void getUsuariosQueVieron(String titulo){
		// Session session = sessions.openSession();
		Transaction tx = null;
		try {
			Query query = session.createQuery(
					"select distinct u.email " +
					"from Usuario u inner join u.gestor g inner join g.reproducciones r " +
					",Episodio e " +
			        "where  r.Reproducible.class='Episodio' and r.Reproducible.id=e.id and e.titulo=:tit");
			
			query.setParameter("tit", titulo);
			
			tx = session.beginTransaction();
			List list =  query.list();
			tx.commit();

			System.out.println("-----------------------------------------------------------------------------");
			System.out.println("h. Listar los usuarios que vieron un episodio del siguiente titulo: "+titulo);
			System.out.println("-----------------------------------------------------------------------------");
			
			Iterator iter = list.iterator();
			while( iter.hasNext()){
				Object obj= (Object) iter.next();
				System.out.println("   Mail del usuario: " +  (String)obj);
			}

		} catch (Exception e) {
			e.printStackTrace();
			if (tx != null) {
				tx.commit();
			}
			//session.close();
		}
		//session.disconnect();
		
		System.out.println("-----------------------------------------------------------------------------");
	}
	
	
	/**
	 * @return Listar usuarios que reprodujeron al menos una película cuya edad mínima sea 12 años. 
	 * Imprimir en consola:"Mail del usuario: "
	 */
	private static void getUsuariosEdadm12QueVieronAlmenos1Peli(){
		Transaction tx = null;
		try {
			Query query = session.createQuery(
					"select distinct u.email " +
					"from Usuario u inner join u.gestor g inner join g.reproducciones r " +
					",Pelicula p " +
			        "where  r.Reproducible.class='Pelicula' and r.Reproducible.id=p.id and p.edadMinima=12");
			
			tx = session.beginTransaction();
			List list =  query.list();
			tx.commit();

			System.out.println("-----------------------------------------------------------------------------");
			System.out.println("i. Listar usuarios que reprodujeron al menos una película cuya edad mínima sea 12 años.");
			System.out.println("-----------------------------------------------------------------------------");
			
			Iterator iter = list.iterator();
			while( iter.hasNext()){
				Object obj= (Object) iter.next();
				System.out.println("   Mail del usuario: " +  (String)obj);
			}

		} catch (Exception e) {
			e.printStackTrace();
			if (tx != null) {
				tx.commit();
			}
		}
		
		System.out.println("-----------------------------------------------------------------------------");
	}
	
	/*
	 *  Listar los usuarios que estén a menos de una cantidad dada de reproducciones para llegar
al límite de las mismas para su categoría. Imprimir en consola:"Mail del usuario: "

	 * */
	
	private static void getUsuariosAlimiteDeUnaCategoria(int limite){
		Transaction tx = null;
		try {
			Query query = session.createQuery(
					"select distinct u.email  "+
					"from Usuario u inner join u.gestor g inner join g.reproducciones r "+
					"where (u.suscripcion.categoria.limite-r.size)<=:limit_repro"
					);
			query.setParameter("limit_repro", limite);
			tx = session.beginTransaction();
			List list =  query.list();
			tx.commit();

			System.out.println("-----------------------------------------------------------------------------");
			System.out.println("j. Listar usuarios que estén a menos de "+ limite+" reproducciones de llegar al límite de su categoría");
			System.out.println("-----------------------------------------------------------------------------");
			
			Iterator iter = list.iterator();
			while( iter.hasNext()){
				//Object[] objs= (Object[]) iter.next();
				//System.out.println("   Mail del usuario: " +  (String)objs[0] + " Cantidad: "+(Integer)objs[1]+
				//		" limite categoria: "+objs[2].toString() );
				Object obj= (Object) iter.next();
				System.out.println("   Mail del usuario: " + obj.toString());	
			}

		} catch (Exception e) {
			e.printStackTrace();
			if (tx != null) {
				tx.commit();
			}
		}
		
		System.out.println("-----------------------------------------------------------------------------");
	}
	
	
	
}
